#!/usr/bin
# -*- coding: utf-8 -*-


# ==============================================================================
class Node():
    """ A node does not have any name.
    Its collection manage that. """
    
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z


# ==============================================================================
class Q8():
    """ An element does not have any name.
    """
    
    def __init__(self, n1, n2, n3, n4, n5, n6, n7, n8):
        self.n1 = n1
        self.n2 = n2
        self.n3 = n3
        self.n4 = n4
        self.n5 = n5
        self.n6 = n6
        self.n7 = n7
        self.n7 = n7




# ==============================================================================
class Edge():
    def __init__(self, startNode, endNode):
        self.sn = startNode
        self.en = endNode
    
    def createUnitVector(self, nodes):
        S = nodes[self.sn]
        E = nodes[self.en]
        SE = (EN[0]-SN[0], EN[1]-SN[1], EN[2]-SN[2])
        nSE = msqrt(SNEN[0]**2 + SNEN[1]**2 + SNEN[2]**2)
        try:
            self.u = (SE[0]/nSE, SE[1]/nSE, SE[2]/nSE)
        except:
            raise ValueError, "Nul length edge between nodes %i and %i" % (self.sn, self.en)


# ==============================================================================
class Domain():
    def __init__(self, elements, cornerNodes):
        self.elements = elements
        self.cornerNodes = cornerNodes

    def computeEdges(self, nodes):
        self.edges = []
        
        a = self.cornerNodes
        a.append(a[-1])
        for i in xrange(len(a)-1):
            self.edges.append(Edge(a[i], a[i+1]))







# ------------------------------------------------------------------------------
def readBlankLine(line, iLine, args):
    pass

# ------------------------------------------------------------------------------
def readNode(line, iLine, args):
    try:
        ndIdU, nx, ny, nz = line[1:]
        try:
            nx, ny, nz = float(nx), float(ny), float(nz)
        except:
            raise ValueError, "Line "  + str(iLine) + \
                              ": reading node failure\n" + \
                              "> coordinates of nodes must be floats"
    except:
        raise ValueError, "Line " + str(iLine) + \
                          ": reading node failure\n" + \
                          "> node is defined by: nodeId,x,y,z"
    try:
        a = args["ndsU2C"][ndIdU]
        print "Error line " + str(iLine) + ": node " + ndIdU + \
              " already exists"
    except:
        args["ndsU2C"][ndIdU] = args["iNodes"]
        args["ndsC2U"].append(ndIdU)
        args["ndsC"].append(tuple([nx,ny,nz]))
        args["iNodes"] += 1

# ------------------------------------------------------------------------------
def readElement(line, iLine, args):
    try:
        elTypeU, scIdU, elIdU, ndsIdsU = line[1], line[2], line[3], line[4:]
    except:
        raise ValueError, "Line " + str(iLine) + \
                          ": reading element failure\n" + \
                          "> element is defined by: sectionId," + \
                          "elementId,elementNodesIds"
    try:
        a = args["elsU2C"][elIdU]
        print "Error line " + str(iLine) + ": element " + elIdU + \
              " already exists"
    except:
        args["elsU2C"][elIdU] = args["iElements"]
        args["elsC2U"].append(elIdU)
        args["elsC"].append(tuple([ndsU2C[ndIdU] for ndIdU in ndsIdsU]))
        args["iElements"] += 1

# ------------------------------------------------------------------------------
def readDomain(line, iLine, args):
    try:
        domIdU, elsIdsU = line[1], line[2:]
    except:
        raise ValueError, "Line " + str(iLine) + \
                          ": reading domain failure" + \
                          "> domain is defined by: domainId," + \
                          "domainElementsIds"
    try:
        domIdC = args["domsU2C"][domIdU]
        for elIdU in elsIdsU:
            args["domsC"][domIdC].append(args["elsU2C"][elIdU])
    except:
        args["domsU2C"][domIdU] = args["iDomains"]
        args["domsC2U"].append(domIdU)
        args["domsC"].append(tuple([args["elsU2C"][elIdU] for elIdU in elsIdsU]))
        args["iDomains"] += 1

# ------------------------------------------------------------------------------
def readTopologicDomain(line, iLine, args):
    "A vocation à disparaître ou au moins à être automatisé à terme"
    try:
        topDomIdU, ndsIdsU = line[1], line[2:]
    except:
        raise ValueError, "Line " + str(iLine) + \
                          ": reading topologic domain failure" + \
                          "> topologic domain is defined by: topologicDomainId," + \
                          "topologicDomainCornersNodesIds"
    try:
        tdIdC = args["topDomsU2C"][topDomIdU]
        for ndIdU in ndsIdsU:
            args["topDomsC"].append(args["ndsU2C"][ndIdU])
    except:
        args["topDomsU2C"][topDomIdU] = args["iTopologicDomains"]
        args["topDomsC2U"].append(topDomIdU)
        args["topDomsC"].append([args["ndsU2C"][ndIdU] for ndIdU in ndsIdsU])
        args["iTopologicDomains"] += 1

# ------------------------------------------------------------------------------
def readSection(line, iLine, args):
    raise NotImplementedError, "Sections not available yet"

# ------------------------------------------------------------------------------
def readMaterial(line, iLine, args):
    raise NotImplementedError, "Materials not available yet"

# ------------------------------------------------------------------------------
def readBoundaryCondition(line, iLine, args):
    raise NotImplementedError, "Boundary conditions not available yet"

# ------------------------------------------------------------------------------
def readLoadCondition(line, iLine, args):
    raise NotImplementedError, "Load conditions not available yet"

# ------------------------------------------------------------------------------
parsingFunctions = {"": readBlankLine,
                    "n": readNode,
                    "e": readElement,
                    "d": readDomain,
                    "td": readTopologicDomain,
                    "s": readSection,
                    "m": readMaterial,
                    "bc": readBoundaryCondition,
                    "lc": readLoadCondition}

# ------------------------------------------------------------------------------
def readGlobalNumFile(fileName, args):
    try:
        myFile = open(fileName, "r")
    except:
        raise InputError, "Can not open " + fileName

    args["iNodes"] = 0
    args["iElements"] = 0
    args["iDomains"] = 0
    args["iTopologicDomains"] = 0

    iLine = 0
    while True:
        line = myFile.readline()
        if not line:
            break

        iLine += 1
        line = line.replace("\n","")
        line = line.replace("\r","")
        line = line.replace(" ", "")
        line = line.split(",")

        key = line[0].lower()
        try:
            parsingFunctions[key](line, iLine, args)
        except:
            raise ValueError, "Line " + str(iLine) + " must start with " + str(parsingFunctions.keys())
    myFile.close()

# ------------------------------------------------------------------------------
def enrichConnectivity(args):
    # ndsC from domC
    for domIdC in args["domsC"]:
        args["ndsCFromDomC"].append({}) # on est obligé de créer a priori
    for domIdC, elsIdsC in enumerate(args["domsC"]):
        for elIdC in elsIdsC:
            ndsIdsC = args["elsC"][elIdC]
            for ndIdC in ndsIdsC:
                try:
                    a = args["ndsCFromDomC"][domIdC][ndIdC]
                except:
                    args["ndsCFromDomC"][domIdC][ndIdC] = None
        args["ndsCFromDomC"][domIdC] = tuple(args["ndsCFromDomC"][domIdC].keys())

    # elsC from ndC
    for ndIdC in args["ndsC"]:
        args["elsCFromNdC"].append({})
    for elIdC, ndsIdsC in enumerate(args["elsC"]):
        for ndIdC in ndsIdsC:
            try:
                a = args["elsCFromNdC"][ndIdC][elIdC]
            except:
                args["elsCFromNdC"][ndIdC][elIdC] = None

    # domsC from elC
    for elIdC in args["elsC"]:
        args["domCFromElC"].append(None)
    for domIdC, elsIdsC in enumerate(args["domsC"]):
        for elIdC in elsIdsC:
            args["domCFromElC"][elIdC] = domIdC

    # domsC from ndC
    for ndIdC in args["ndsC"]:
        args["domsCFromNdC"].append({})
    for elIdC, domIdC in enumerate(args["domCFromElC"]):
        ndsIdsC = args["elsC"][elIdC]
        for ndIdC in ndsIdsC:
            try:
                a = args["domsCFromNdC"][ndIdC][domIdC]
            except:
                args["domsCFromNdC"][ndIdC][domIdC] = None

    for ndIdC in xrange(len(args["ndsC"])):
        args["elsCFromNdC"][ndIdC] = tuple(args["elsCFromNdC"][ndIdC].keys())
        args["domsCFromNdC"][ndIdC] = tuple(args["domsCFromNdC"][ndIdC].keys())



# ------------------------------------------------------------------------------
def buildDomainsBoundaries(args):
    args["topDomsEdgesC"] = []
    
    for topDom in args["topDomsC"]:
        topDom.append(topDom[-1])
        for i in xrange(len(topDom)-1):
            A, B = topDom[i], topDom[i+1]
            A, B = args["ndsC"][A], args["ndsC"][B]
            AB = (B[0]-A[0], B[1]-A[1], B[2]-A[2])
            nAB = msqrt(AB[0]**2 + AB[1]**2 + AB[2]**2)
            try:
                uAB = (AB[0]/nAB, AB[1]/nAB, AB[2]/nAB)
            except:
                raise ValueError, "edge de longueur nulle"



# ==============================================================================
if __name__ == "__main__":
    from math import sqrt as msqrt

    EPSILON = 1.0e-6
    ABAQUS_MAX_ARGS_PER_LINE = 16

    fileName = "maillage2.dat"

    # Données brutes du fichier
    ndsC, ndsC2U, ndsU2C = [], [], {}
    elsC, elsC2U, elsU2C = [], [], {}
    domsC, domsC2U, domsU2C = [], [], {}
    topDomsC, topDomsC2U, topDomsU2C = [], [], {}

    # Connectivité complémentaire
    ndsCFromDomC = []
    elsCFromNdC = []
    domCFromElC = []
    domsCFromNdC = []

    # Données rassemblées dans dictionnaire (accès par adresse)
    args = {"ndsC":ndsC,
            "ndsC2U":ndsC2U,
            "ndsU2C":ndsU2C,
            "elsC":elsC,
            "elsC2U":elsC2U,
            "elsU2C":elsU2C,
            "domsC":domsC,
            "domsC2U":domsC2U,
            "domsU2C":domsU2C,
            "topDomsC":topDomsC,
            "topDomsC2U":topDomsC2U,
            "topDomsU2C":topDomsU2C,
            "ndsCFromDomC":ndsCFromDomC,
            "elsCFromNdC":elsCFromNdC,
            "domCFromElC":domCFromElC,
            "domsCFromNdC":domsCFromNdC}

    readGlobalNumFile(fileName, args)
    enrichConnectivity(args)

    buildDomainsBoundaries(args)

    print "ndsC\n", args["ndsC"]
    print "ndsU2C\n", args["ndsU2C"]
    print "ndsC2U\n", args["ndsC2U"]

    print "\n\n"

    print "elsC\n", args["elsC"]
    print "elsU2C\n", args["elsU2C"]
    print "elsC2U\n", args["elsC2U"]

    print "\n\n"

    print "domsC\n", args["domsC"]
    print "domsU2C\n", args["domsU2C"]
    print "domsC2U\n", args["domsC2U"]

    print "\n\n"

    print "topDomsC\n", args["topDomsC"]
    print "topDomsU2C\n", args["topDomsU2C"]
    print "topDomsC2U\n", args["topDomsC2U"]

    print "\n\n"

    print "ndsCFromDomC\n", args["ndsCFromDomC"]
    print "elsCFromNdC\n", args["elsCFromNdC"]
    print "domCFromElC\n", args["domCFromElC"]
    print "domsCFromNdC\n", args["domsCFromNdC"]
